package org.dromara.application.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.application.domain.AppUser;
import org.dromara.application.mapper.AppUserMapper;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.dto.UserDTO;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.service.UserService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.OpenIdGenerator;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;
import org.dromara.application.domain.bo.ApplicationBo;
import org.dromara.application.domain.vo.ApplicationVo;
import org.dromara.application.domain.Application;
import org.dromara.application.mapper.ApplicationMapper;
import org.dromara.application.service.IApplicationService;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Collection;

/**
 * 应用管理Service业务层处理
 *
 * @author YCJZ
 * @date 2025-09-16
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class ApplicationServiceImpl implements IApplicationService {

    private final ApplicationMapper baseMapper;
    private final AppUserMapper appUserMapper;

    /**
     * 查询应用管理
     *
     * @param appId 主键
     * @return 应用管理
     */
    @Override
    public ApplicationVo queryById(Long appId){
        return baseMapper.selectVoById(appId);
    }

    /**
     * 查询应用管理
     *
     * @param clientId clientId
     * @return 应用管理
     */
    @Override
    public ApplicationVo getByClientId(String clientId) {
        return baseMapper.selectVoOne(new LambdaQueryWrapper<Application>().eq(Application::getClientId, clientId));
    }

    /**
     * 分页查询应用管理列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 应用管理分页列表
     */
    @Override
    public TableDataInfo<ApplicationVo> queryPageList(ApplicationBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Application> lqw = buildQueryWrapper(bo);
        Page<ApplicationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询应用列表
     *
     * @return 应用列表
     */
    @Override
    public List<ApplicationVo> getAppList(Long appTypeId) {
        return baseMapper.selectVoListXml(LoginHelper.getUserId(), appTypeId);
    }

    /**
     * 查询符合条件的应用管理列表
     *
     * @param bo 查询条件
     * @return 应用管理列表
     */
    @Override
    public List<ApplicationVo> queryList(ApplicationBo bo) {
        LambdaQueryWrapper<Application> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Application> buildQueryWrapper(ApplicationBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Application> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(Application::getAppId);
        lqw.like(StringUtils.isNotBlank(bo.getAppName()), Application::getAppName, bo.getAppName());
        lqw.eq(bo.getAppTypeId() != null, Application::getAppTypeId, bo.getAppTypeId());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Application::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增应用管理
     *
     * @param bo 应用管理
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(ApplicationBo bo) {
        Application add = MapstructUtils.convert(bo, Application.class);
        validEntityBeforeSave(add);
        add.setClientId(IdUtil.simpleUUID());
        add.setClientSecret(IdUtil.simpleUUID());
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setAppId(add.getAppId());
        }
        return flag;
    }

    /**
     * 修改应用管理
     *
     * @param bo 应用管理
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(ApplicationBo bo) {
        Application update = MapstructUtils.convert(bo, Application.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(Application entity){
        //TODO 做一些数据校验,如唯一约束
        if (StringUtils.isNotBlank(entity.getAppName())
            && checkAppNameUnique(entity)) {
            throw new ServiceException("操作应用'" + entity.getAppName() + "'失败, 应用已存在!");
        }
    }

    /**
     * 校验应用名称唯一
     */
    private boolean checkAppNameUnique(Application entity) {
        return baseMapper.exists(new LambdaQueryWrapper<Application>()
            .eq(Application::getAppName, entity.getAppName())
            .eq(Application::getAppTypeId, entity.getAppTypeId())
            .ne(ObjectUtil.isNotNull(entity.getAppId()), Application::getAppId, entity.getAppId()));
    }

    /**
     * 校验并批量删除应用管理信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 查询已分配用户应用列表
     *
     * @param clientId clientId
     * @param userName 用户名
     * @param phonenumber 手机号码
     * @param pageQuery 分页参数
     * @return 应用管理列表
     */
    @Override
    public TableDataInfo<UserDTO> selectAllocatedList(String clientId, String userName, String phonenumber, PageQuery pageQuery) {
        QueryWrapper<UserDTO> wrapper = Wrappers.query();
        wrapper.eq("a.client_id", clientId);
        wrapper.like(StringUtils.isNotBlank(userName), "u.user_name", userName);
        wrapper.like(StringUtils.isNotBlank(phonenumber), "u.phonenumber", phonenumber);
        wrapper.eq("u.del_flag", SystemConstants.NORMAL);
        Page<UserDTO> page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 查询未分配用户应用列表
     *
     * @param clientId clientId
     * @param userName 用户名
     * @param phonenumber 手机号码
     * @param pageQuery 分页参数
     * @return 应用管理列表
     */
    @Override
    public TableDataInfo<UserDTO> selectUnallocatedList(String clientId, String userName, String phonenumber, PageQuery pageQuery) {
        QueryWrapper<UserDTO> wrapper = Wrappers.query();
        wrapper.and(w -> w.ne("a.client_id", clientId).or().isNull("a.client_id"));
        wrapper.like(StringUtils.isNotBlank(userName), "u.user_name", userName);
        wrapper.like(StringUtils.isNotBlank(phonenumber), "u.phonenumber", phonenumber);
        wrapper.eq("u.del_flag", SystemConstants.NORMAL);
        Page<UserDTO> page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 取消授权用户
     *
     * @param clientId clientId
     * @param userIds  用户ID
     * @return 影响行数
     */
    @Override
    public int deleteAuthUsers(String clientId, Long[] userIds) {
        List<Long> ids = List.of(userIds);
        return appUserMapper.delete(new LambdaQueryWrapper<AppUser>()
            .eq(AppUser::getClientId, clientId)
            .in(AppUser::getUserId, ids));
    }

    /**
     * 批量授权用户
     *
     * @param clientId clientId
     * @param userIds  用户ID
     * @return 影响行数
     */
    @Override
    public boolean insertAuthUsers(String clientId, Long[] userIds) {
        List<AppUser> list = new ArrayList<>();
        for (Long userId : userIds) {
            AppUser appUser = new AppUser();
            appUser.setClientId(clientId);
            appUser.setUserId(userId);
            appUser.setOpenId(OpenIdGenerator.generate32BitOpenId(String.valueOf(userId), clientId));
            list.add(appUser);
        }
        return appUserMapper.insertBatch(list);
    }
}
